import { fxDebug } from './debug'
const _log = fxDebug('fxUtils')
const _toString = Object.prototype.toString
// 类型检查  by shw
const toRawType = function <T> (value: T): string {
	return _toString.call(value).slice(8, -1)
}

// 判断是数组
const isArray = Array.isArray

// 判断是map
const isMap = <T> (val: T): boolean => toRawType(val) === 'Map'

// 判断是set
const isSet = <T> (val: T): boolean => toRawType(val) === 'Set'

// 判断是日期对象
const isDate = (val: unknown): val is Date => val instanceof Date

// 判断是function
const isFunction = <T> (val: T): boolean => typeof val === 'function'

// 判断是string
const isString = <T> (val: T): boolean => typeof val === 'string'

// 判断是symbol
const isSymbol = <T> (val: T): boolean => typeof val === 'symbol'

// 判断是Boolean
const isBoolean = <T> (val: T): boolean => typeof val === 'boolean'

// 判断是对象
const isObject = <T> (val: T): boolean => val !== null && typeof val === 'object'

// 判断是否为一个纯粹对象
const isPlainObject = (val: object): boolean => toRawType(val) === 'Object'

// 判断空对象 by shw
const isEmptyObj = function (obj: object): boolean {
	if (toRawType(obj) !== 'Object') {
		throw new Error('this is not object')
	}
	for (const key in obj) {
		if (Object.prototype.hasOwnProperty.call(obj, key)) {
			return false
		}
	}
	return true
}
// JSON解析 by shw
const JSONparse = function <T> (jsonStr: string, type?: string): T {
	try {
		const obj = JSON.parse(jsonStr)
		if (type === 'object' && typeof obj !== 'object') {
			return {} as T
		}
		return obj
	} catch (error) {
		if (type === 'object') {
			return {} as T
		}
		return undefined as T
	}
}
// 判断undefined/null by shw
const isDef = function <T> (value: T): boolean {
	return value !== undefined && value !== null
}
// 转布尔类型
const toBoolean = <T> (value: T, truethArr = []): boolean => {
	if (typeof value === 'string') {
		const _value = value.trim().toLowerCase()
		return _value === 'true' || _value === '1' || _value === 'yes' || truethArr.some(item => item === _value)
	} else if (typeof value === 'boolean') {
		return value
	} else if (typeof value === 'number') {
		return !!value
	} else {
		return !!value
	}
}
const deepClone = function <T> (target: T): T {
	if (Array.isArray(target)) {
		return target.map(item => deepClone(item)) as unknown as T
	}
	if (isObject(target)) {
		const result: Record<string, unknown> = {}
		for (const key in target) {
			if (Object.prototype.hasOwnProperty.call(target, key)) {
				result[key] = deepClone(target[key])
			}
		}
		return result as T
	} else {
		return target
	}
}

// 判断两个数据完全相等 by shw
const compare = function (origin: { [key: string]: {} }, target: { [key: string]: {} }, log = false): boolean {
	if (typeof target !== 'object' || target === null) {
		const val = origin === target
		if (log && !val) {
			_log(`valpre:${origin},valcur:${target}`)
		}
		return val
	}
	if (typeof origin !== 'object') {
		if (log) {
			_log('origin类型错误')
		}
		return false
	}
	if (Object.keys(origin).length !== Object.keys(target).length) {
		if (log) {
			const originKeys = Object.keys(origin)
			const targetKeys = Object.keys(target)
			const originKeysDiff = originKeys.filter(item => {
				return !~targetKeys.indexOf(item)
			})
			const targetKeysDiff = targetKeys.filter(item => {
				return !~originKeys.indexOf(item)
			})
			const keys = Array.from(new Set([...originKeysDiff, ...targetKeysDiff]))
			_log(`key数量不等,keys:${keys.join(',')}`)
		}
		return false
	}
	for (const key of Object.keys(target)) {
		if (!compare(origin[key], target[key])) {
			if (log) {
				_log(`key:${key},valpre:, ${origin[key]}, ' ,valcur:', ${target[key]}`)
			}
			return false
		}
	}
	return true
}
// 数组转对象
const fromEntries = function (arr: never[]): object {
	const obj = {}
	arr.forEach(item => {
		obj[item[0]] = item[1]
	})
	return obj
}
// 获取深层属性
const getObjDeepValue = function <T, K> (obj: string | { [key: string]: unknown } | K, prop: string, defaultValue = ''): T {
	if (~prop.indexOf('.')) {
		return prop.split('.').reduce((pre: string | { [key: string]: never }, cur: string) => {
			return !isDef(pre) ? defaultValue : (pre as { [key: string]: never })[cur]
		}, obj as string) as T
	}
	return isDef((obj as { [key: string]: unknown })[prop]) ? (obj as { [key: string]: unknown })[prop] as T : defaultValue as T
}
export default {
	toRawType,
	isArray,
	isMap,
	isSet,
	isDate,
	isFunction,
	isString,
	isSymbol,
	isBoolean,
	isObject,
	isPlainObject,
	isEmptyObj,
	JSONparse,
	isDef,
	deepClone,
	compare,
	fromEntries,
	getObjDeepValue,
	toBoolean
}
